import java.util.ArrayList;
import java.util.Map;

public class Instruction {

	ArrayList<Integer> asMemory = new ArrayList<Integer>();
	assembler as;

	public void parser(String line, int index) {
		for (int i = 0; i < line.length(); i++)
			if (line.charAt(i) == '#') {
				line = line.substring(0, i);
				break;
			}

		String[] l = line.split("[\\s,]+");
		if (l.length > 4 || l.length < 2)
			methods.error(index);

		switch (l[0]) {
		case "add":
			if (l.length == 4)
				add(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "addi":
			if (l.length == 4)
				addi(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "sub":
			if (l.length == 4)
				sub(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "lw":
			if (l.length == 3)
				lw(l[1], l[2], index);
			else
				methods.error(index);
			break;
		case "sw":
			if (l.length == 3)
				sw(l[1], l[2], index);
			else
				methods.error(index);
			break;
		case "sll":
			if (l.length == 4)
				sll(l[1], l[2], l[3], index);
			else
				methods.error(index);
		case "srl":
			if (l.length == 4)
				srl(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "and":
			if (l.length == 4)
				and(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "andi":
			if (l.length == 4)
				andi(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "or":
			if (l.length == 4)
				or(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "ori":
			if (l.length == 4)
				ori(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "nor":
			if (l.length == 4)
				nor(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "slt":
			if (l.length == 4)
				slt(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "slti":
			if (l.length == 4)
				slti(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "sltu":
			if (l.length == 4)
				sltu(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		case "sltui":
			if (l.length == 4)
				sltui(l[1], l[2], l[3], index);
			else
				methods.error(index);
			break;
		default:
			methods.error(index);
			break;
		}
	}

	public void add(String destination, String src1, String src2, int index) {
		int x = 0;
		if (methods.checkPresence(destination, as.reg, index) && methods.checkPresence(src1, as.reg, index)
				&& methods.checkPresence(src2, as.reg, index))
					x = as.reg.get(src1) + as.reg.get(src2);
						as.reg.put(destination, x);
	}

	public void addi(String destination, String src1, String imm, int index) {
		int x = 0;
		int y = 0;
		try {
			x = Integer.parseInt(imm);
		} catch (NumberFormatException e) {
			methods.error(index);
		}
		if (methods.checkPresence(destination, as.reg, index) && methods.checkPresence(src1, as.reg, index))
					y = as.reg.get(src1) + x;
						as.reg.put(destination, y);
		  
	}

	public void sub(String destination, String src1, String src2, int index) {
		int x = 0;
		if (methods.checkPresence(destination, as.reg, index) && methods.checkPresence(src1, as.reg, index)
				&& methods.checkPresence(src2, as.reg, index))
					x = as.reg.get(src1) - as.reg.get(src2);
						as.reg.put(destination, x);
	}

	public void lw(String register, String memory, int index) {
		if (methods.checkPresence(register, as.reg , index) && methods.checkMemo(memory, index)){
			String mem [] = methods.getMemo(memory); 
			if(methods.checkPresence(mem[0], as.reg , index))
			try { 
				int memoryIndex = Integer.parseInt(mem[0]) + as.reg.get(mem[1]);
				as.reg.put(register, asMemory.get(memoryIndex));
			
			} catch (NumberFormatException e) {
				methods.error(index);
				}
			}
			
	}

	public void sw(String register, String memory, int index) {
		if (methods.checkPresence(register, as.reg , index) && methods.checkMemo(memory, index)){
			String mem [] = methods.getMemo(memory); 
			if(methods.checkPresence(mem[0], as.reg , index))
			try { 
				int memoryIndex = Integer.parseInt(mem[0]) + as.reg.get(mem[1]);
				asMemory.add(memoryIndex, as.reg.get(register));
			
			} catch (NumberFormatException e) {
				methods.error(index);
				}
			}
	}

	public void sll(String destination, String src1, String ShiftAmount, int index) {
		int x = 0;
		try {
			x = Integer.parseInt(ShiftAmount);
		} catch (NumberFormatException e) {
			methods.error(index);
		}
		if(methods.checkPresence(destination, as.reg, index) 
				   && methods.checkPresence(src1, as.reg, index))
				{
					int number = as.reg.get(src1);
					int result = (number << x);
					as.reg.put(destination,result);
				}
	}
			
	

	public void srl(String destination, String src1, String ShiftAmount, int index) {
        
		int x = 0;
		try {
			x = Integer.parseInt(ShiftAmount);
		} catch (NumberFormatException e) {
			methods.error(index);
		}
		if(methods.checkPresence(destination, as.reg, index) 
				   && methods.checkPresence(src1, as.reg, index))
				{
					int number = as.reg.get(src1);
					int result = (number >> x);
					as.reg.put(destination,result);
				}
	}

	public void and(String destination, String src1, String src2, int index) {
     if(methods.checkPresence(destination, as.reg, index) 
        && methods.checkPresence(src1, as.reg, index) && methods.checkPresence(src2, as.reg, index))
     {
    	 int result = as.reg.get(src1) & as.reg.get(src2);
    	 as.reg.put(destination, result);
     }
	}

	public void andi(String destination, String src1, String imm, int index) {
		int x = 0;
		try {
			x = Integer.parseInt(imm);
		} catch (NumberFormatException e) {
			methods.error(index);
		}
		if(methods.checkPresence(src1, as.reg, index)&& methods.checkPresence(destination, as.reg, index))
				{
			      int result = as.reg.get(src1) & x;
			      as.reg.put(destination, result);
			       
				}
	}

	public void or(String destination, String src1, String src2, int index) {
		if (methods.checkPresence(destination, as.reg, index) 
				&& methods.checkPresence(src1, as.reg, index) 
				&& methods.checkPresence(src2, as.reg, index)){
			as.reg.put(destination, as.reg.get(src1) | as.reg.get(src2));
		}
	}

	public void ori(String destination, String src1, String imm, int index) {
		int x = 0;
		try {
			x = Integer.parseInt(imm);
		} catch (NumberFormatException e) {
			methods.error(index);
		}
		if (methods.checkPresence(destination, as.reg, index) 
				&& methods.checkPresence(src1, as.reg, index)){
			as.reg.put(destination, as.reg.get(src1) | x);
		}
	}

	public void nor(String destination, String src1, String src2, int index) {
		int result = 0;
		if (methods.checkPresence(destination, as.reg, index) 
				&& methods.checkPresence(src1, as.reg, index) 
				&& methods.checkPresence(src2, as.reg, index)){
			result = ~(as.reg.get(src1) | as.reg.get(src2));
			as.reg.put(destination, result);
		}
	}

	public void slt(String destination, String src1, String src2, int index) {
		if (methods.checkPresence(destination, as.reg, index))
			if (methods.checkPresence(src1, as.reg, index))
				if (methods.checkPresence(src2, as.reg, index))
					if (as.reg.get(src1) < as.reg.get(src2))
						as.reg.put(destination, 1);
					else
						as.reg.put(destination, 0);
	}

	public void slti(String destination, String src1, String imm, int index) {
		int x = 0;
		try {
			x = Integer.parseInt(imm);
		} catch (NumberFormatException e) {
			methods.error(index);
		}
		if (methods.checkPresence(destination, as.reg, index))
			if (methods.checkPresence(src1, as.reg, index))
				if (as.reg.get(src1) < x)
					as.reg.put(destination, 1);
				else
					as.reg.put(destination, 0);
	}

	public void sltu(String destination, String src1, String src2, int index) {
		if (methods.checkPresence(destination, as.reg, index))
			if (methods.checkPresence(src1, as.reg, index))
				if (methods.checkPresence(src2, as.reg, index)) {
					long s1 = methods.unsigned(Integer.toBinaryString(as.reg.get(src1)));
					long s2 = methods.unsigned(Integer.toBinaryString(as.reg.get(src2)));
					if (s1 < s2)
						as.reg.put(destination, 1);
					else
						as.reg.put(destination, 0);
				}

	}

	public void sltui(String destination, String src1, String imm, int index) {
		long x = 0;
		try {
			x = methods.unsigned(imm);
		} catch (NumberFormatException e) {
			methods.error(index);
		}

		if (methods.checkPresence(destination, as.reg, index))
			if (methods.checkPresence(src1, as.reg, index)) {
				long s1 = methods.unsigned(Integer.toBinaryString(as.reg.get(src1)));
				if (s1 < x)
					as.reg.put(destination, 1);
				else
					as.reg.put(destination, 0);
			}
	}

}
